home *** CD-ROM | disk | FTP | other *** search
/ SGI Freeware 2002 November / SGI Freeware 2002 November - Disc 1.iso / dist / fw_emacs-lisp-intro.idb / usr / freeware / info / emacs-lisp-intro.info-10.z / emacs-lisp-intro.info-10
Text File  |  2002-07-08  |  48KB  |  1,116 lines

  1. This is emacs-lisp-intro.info, produced by makeinfo version 4.0b from
  2. emacs-lisp-intro.texi.
  3.  
  4. INFO-DIR-SECTION Emacs
  5. START-INFO-DIR-ENTRY
  6. * Emacs Lisp Intro: (eintr).
  7.               A simple introduction to Emacs Lisp programming.
  8. END-INFO-DIR-ENTRY
  9.  
  10.    This is an introduction to `Programming in Emacs Lisp', for people
  11. who are not programmers.
  12.  
  13.    Edition 2.04, 2001 Dec 17
  14.  
  15.    Copyright (C) 1990, '91, '92, '93, '94, '95, '97, 2001 Free Software
  16. Foundation, Inc.
  17.  
  18.    Permission is granted to copy, distribute and/or modify this document
  19. under the terms of the GNU Free Documentation License, Version 1.1 or
  20. any later version published by the Free Software Foundation; with the
  21. Invariant Section being the Preface, with the Front-Cover Texts being
  22. no Front-Cover Texts, and with the Back-Cover Texts being no Back-Cover
  23. Texts.  A copy of the license is included in the section entitled "GNU
  24. Free Documentation License".
  25.  
  26. 
  27. File: emacs-lisp-intro.info,  Node: Design count-words-region,  Next: Whitespace Bug,  Prev: count-words-region,  Up: count-words-region
  28.  
  29. Designing `count-words-region'
  30. ------------------------------
  31.  
  32.    First, we will implement the word count command with a `while' loop,
  33. then with recursion.  The command will, of course, be interactive.
  34.  
  35.    The template for an interactive function definition is, as always:
  36.  
  37.      (defun NAME-OF-FUNCTION (ARGUMENT-LIST)
  38.        "DOCUMENTATION..."
  39.        (INTERACTIVE-EXPRESSION...)
  40.        BODY...)
  41.  
  42.    What we need to do is fill in the slots.
  43.  
  44.    The name of the function should be self-explanatory and similar to
  45. the existing `count-lines-region' name.  This makes the name easier to
  46. remember.  `count-words-region' is a good choice.
  47.  
  48.    The function counts words within a region.  This means that the
  49. argument list must contain symbols that are bound to the two positions,
  50. the beginning and end of the region.  These two positions can be called
  51. `beginning' and `end' respectively.  The first line of the
  52. documentation should be a single sentence, since that is all that is
  53. printed as documentation by a command such as `apropos'.  The
  54. interactive expression will be of the form `(interactive "r")', since
  55. that will cause Emacs to pass the beginning and end of the region to
  56. the function's argument list.  All this is routine.
  57.  
  58.    The body of the function needs to be written to do three tasks:
  59. first, to set up conditions under which the `while' loop can count
  60. words, second, to run the `while' loop, and third, to send a message to
  61. the user.
  62.  
  63.    When a user calls `count-words-region', point may be at the
  64. beginning or the end of the region.  However, the counting process must
  65. start at the beginning of the region.  This means we will want to put
  66. point there if it is not already there.  Executing `(goto-char
  67. beginning)' ensures this.  Of course, we will want to return point to
  68. its expected position when the function finishes its work.  For this
  69. reason, the body must be enclosed in a `save-excursion' expression.
  70.  
  71.    The central part of the body of the function consists of a `while'
  72. loop in which one expression jumps point forward word by word, and
  73. another expression counts those jumps.  The true-or-false-test of the
  74. `while' loop should test true so long as point should jump forward, and
  75. false when point is at the end of the region.
  76.  
  77.    We could use `(forward-word 1)' as the expression for moving point
  78. forward word by word, but it is easier to see what Emacs identifies as a
  79. `word' if we use a regular expression search.
  80.  
  81.    A regular expression search that finds the pattern for which it is
  82. searching leaves point after the last character matched.  This means
  83. that a succession of successful word searches will move point forward
  84. word by word.
  85.  
  86.    As a practical matter, we want the regular expression search to jump
  87. over whitespace and punctuation between words as well as over the words
  88. themselves.  A regexp that refuses to jump over interword whitespace
  89. would never jump more than one word!  This means that the regexp should
  90. include the whitespace and punctuation that follows a word, if any, as
  91. well as the word itself.  (A word may end a buffer and not have any
  92. following whitespace or punctuation, so that part of the regexp must be
  93. optional.)
  94.  
  95.    Thus, what we want for the regexp is a pattern defining one or more
  96. word constituent characters followed, optionally, by one or more
  97. characters that are not word constituents.  The regular expression for
  98. this is:
  99.  
  100.      \w+\W*
  101.  
  102. The buffer's syntax table determines which characters are and are not
  103. word constituents.  (*Note What Constitutes a Word or Symbol?: Syntax,
  104. for more about syntax.  Also, see *Note Syntax: (emacs)Syntax, and
  105. *Note Syntax Tables: (elisp)Syntax Tables.)
  106.  
  107.    The search expression looks like this:
  108.  
  109.      (re-search-forward "\\w+\\W*")
  110.  
  111. (Note that paired backslashes precede the `w' and `W'.  A single
  112. backslash has special meaning to the Emacs Lisp interpreter.  It
  113. indicates that the following character is interpreted differently than
  114. usual.  For example, the two characters, `\n', stand for `newline',
  115. rather than for a backslash followed by `n'.  Two backslashes in a row
  116. stand for an ordinary, `unspecial' backslash.)
  117.  
  118.    We need a counter to count how many words there are; this variable
  119. must first be set to 0 and then incremented each time Emacs goes around
  120. the `while' loop.  The incrementing expression is simply:
  121.  
  122.      (setq count (1+ count))
  123.  
  124.    Finally, we want to tell the user how many words there are in the
  125. region.  The `message' function is intended for presenting this kind of
  126. information to the user.  The message has to be phrased so that it
  127. reads properly regardless of how many words there are in the region: we
  128. don't want to say that "there are 1 words in the region".  The conflict
  129. between singular and plural is ungrammatical.  We can solve this
  130. problem by using a conditional expression that evaluates different
  131. messages depending on the number of words in the region.  There are
  132. three possibilities: no words in the region, one word in the region,
  133. and more than one word.  This means that the `cond' special form is
  134. appropriate.
  135.  
  136.    All this leads to the following function definition:
  137.  
  138.      ;;; First version; has bugs!
  139.      (defun count-words-region (beginning end)
  140.        "Print number of words in the region.
  141.      Words are defined as at least one word-constituent
  142.      character followed by at least one character that
  143.      is not a word-constituent.  The buffer's syntax
  144.      table determines which characters these are."
  145.        (interactive "r")
  146.        (message "Counting words in region ... ")
  147.      
  148.      ;;; 1. Set up appropriate conditions.
  149.        (save-excursion
  150.          (goto-char beginning)
  151.          (let ((count 0))
  152.      
  153.      ;;; 2. Run the while loop.
  154.            (while (< (point) end)
  155.              (re-search-forward "\\w+\\W*")
  156.              (setq count (1+ count)))
  157.      
  158.      ;;; 3. Send a message to the user.
  159.            (cond ((zerop count)
  160.                   (message
  161.                    "The region does NOT have any words."))
  162.                  ((= 1 count)
  163.                   (message
  164.                    "The region has 1 word."))
  165.                  (t
  166.                   (message
  167.                    "The region has %d words." count))))))
  168.  
  169. As written, the function works, but not in all circumstances.
  170.  
  171. 
  172. File: emacs-lisp-intro.info,  Node: Whitespace Bug,  Prev: Design count-words-region,  Up: count-words-region
  173.  
  174. The Whitespace Bug in `count-words-region'
  175. ------------------------------------------
  176.  
  177.    The `count-words-region' command described in the preceding section
  178. has two bugs, or rather, one bug with two manifestations.  First, if
  179. you mark a region containing only whitespace in the middle of some
  180. text, the `count-words-region' command tells you that the region
  181. contains one word!  Second, if you mark a region containing only
  182. whitespace at the end of the buffer or the accessible portion of a
  183. narrowed buffer, the command displays an error message that looks like
  184. this:
  185.  
  186.      Search failed: "\\w+\\W*"
  187.  
  188.    If you are reading this in Info in GNU Emacs, you can test for these
  189. bugs yourself.
  190.  
  191.    First, evaluate the function in the usual manner to install it.
  192. Here is a copy of the definition.  Place your cursor after the closing
  193. parenthesis and type `C-x C-e' to install it.
  194.  
  195.      ;; First version; has bugs!
  196.      (defun count-words-region (beginning end)
  197.        "Print number of words in the region.
  198.      Words are defined as at least one word-constituent character followed
  199.      by at least one character that is not a word-constituent.  The buffer's
  200.      syntax table determines which characters these are."
  201.        (interactive "r")
  202.        (message "Counting words in region ... ")
  203.      
  204.      ;;; 1. Set up appropriate conditions.
  205.        (save-excursion
  206.          (goto-char beginning)
  207.          (let ((count 0))
  208.      
  209.      ;;; 2. Run the while loop.
  210.            (while (< (point) end)
  211.              (re-search-forward "\\w+\\W*")
  212.              (setq count (1+ count)))
  213.      
  214.      ;;; 3. Send a message to the user.
  215.            (cond ((zerop count)
  216.                   (message "The region does NOT have any words."))
  217.                  ((= 1 count) (message "The region has 1 word."))
  218.                  (t (message "The region has %d words." count))))))
  219.  
  220.    If you wish, you can also install this keybinding by evaluating it:
  221.  
  222.      (global-set-key "\C-c=" 'count-words-region)
  223.  
  224.    To conduct the first test, set mark and point to the beginning and
  225. end of the following line and then type `C-c =' (or `M-x
  226. count-words-region' if you have not bound `C-c ='):
  227.  
  228.          one   two  three
  229.  
  230. Emacs will tell you, correctly, that the region has three words.
  231.  
  232.    Repeat the test, but place mark at the beginning of the line and
  233. place point just _before_ the word `one'.  Again type the command `C-c
  234. =' (or `M-x count-words-region').  Emacs should tell you that the
  235. region has no words, since it is composed only of the whitespace at the
  236. beginning of the line.  But instead Emacs tells you that the region has
  237. one word!
  238.  
  239.    For the third test, copy the sample line to the end of the
  240. `*scratch*' buffer and then type several spaces at the end of the line.
  241. Place mark right after the word `three' and point at the end of line.
  242. (The end of the line will be the end of the buffer.)  Type `C-c =' (or
  243. `M-x count-words-region') as you did before.  Again, Emacs should tell
  244. you that the region has no words, since it is composed only of the
  245. whitespace at the end of the line.  Instead, Emacs displays an error
  246. message saying `Search failed'.
  247.  
  248.    The two bugs stem from the same problem.
  249.  
  250.    Consider the first manifestation of the bug, in which the command
  251. tells you that the whitespace at the beginning of the line contains one
  252. word.  What happens is this: The `M-x count-words-region' command moves
  253. point to the beginning of the region.  The `while' tests whether the
  254. value of point is smaller than the value of `end', which it is.
  255. Consequently, the regular expression search looks for and finds the
  256. first word.  It leaves point after the word.  `count' is set to one.
  257. The `while' loop repeats; but this time the value of point is larger
  258. than the value of `end', the loop is exited; and the function displays
  259. a message saying the number of words in the region is one.  In brief,
  260. the regular expression search looks for and finds the word even though
  261. it is outside the marked region.
  262.  
  263.    In the second manifestation of the bug, the region is whitespace at
  264. the end of the buffer.  Emacs says `Search failed'.  What happens is
  265. that the true-or-false-test in the `while' loop tests true, so the
  266. search expression is executed.  But since there are no more words in
  267. the buffer, the search fails.
  268.  
  269.    In both manifestations of the bug, the search extends or attempts to
  270. extend outside of the region.
  271.  
  272.    The solution is to limit the search to the region--this is a fairly
  273. simple action, but as you may have come to expect, it is not quite as
  274. simple as you might think.
  275.  
  276.    As we have seen, the `re-search-forward' function takes a search
  277. pattern as its first argument.  But in addition to this first,
  278. mandatory argument, it accepts three optional arguments.  The optional
  279. second argument bounds the search.  The optional third argument, if
  280. `t', causes the function to return `nil' rather than signal an error if
  281. the search fails.  The optional fourth argument is a repeat count.  (In
  282. Emacs, you can see a function's documentation by typing `C-h f', the
  283. name of the function, and then <RET>.)
  284.  
  285.    In the `count-words-region' definition, the value of the end of the
  286. region is held by the variable `end' which is passed as an argument to
  287. the function.  Thus, we can add `end' as an argument to the regular
  288. expression search expression:
  289.  
  290.      (re-search-forward "\\w+\\W*" end)
  291.  
  292.    However, if you make only this change to the `count-words-region'
  293. definition and then test the new version of the definition on a stretch
  294. of whitespace, you will receive an error message saying `Search failed'.
  295.  
  296.    What happens is this: the search is limited to the region, and fails
  297. as you expect because there are no word-constituent characters in the
  298. region.  Since it fails, we receive an error message.  But we do not
  299. want to receive an error message in this case; we want to receive the
  300. message that "The region does NOT have any words."
  301.  
  302.    The solution to this problem is to provide `re-search-forward' with
  303. a third argument of `t', which causes the function to return `nil'
  304. rather than signal an error if the search fails.
  305.  
  306.    However, if you make this change and try it, you will see the message
  307. "Counting words in region ... " and ... you will keep on seeing that
  308. message ..., until you type `C-g' (`keyboard-quit').
  309.  
  310.    Here is what happens: the search is limited to the region, as before,
  311. and it fails because there are no word-constituent characters in the
  312. region, as expected.  Consequently, the `re-search-forward' expression
  313. returns `nil'.  It does nothing else.  In particular, it does not move
  314. point, which it does as a side effect if it finds the search target.
  315. After the `re-search-forward' expression returns `nil', the next
  316. expression in the `while' loop is evaluated.  This expression
  317. increments the count.  Then the loop repeats.  The true-or-false-test
  318. tests true because the value of point is still less than the value of
  319. end, since the `re-search-forward' expression did not move point. ...
  320. and the cycle repeats ...
  321.  
  322.    The `count-words-region' definition requires yet another
  323. modification, to cause the true-or-false-test of the `while' loop to
  324. test false if the search fails.  Put another way, there are two
  325. conditions that must be satisfied in the true-or-false-test before the
  326. word count variable is incremented: point must still be within the
  327. region and the search expression must have found a word to count.
  328.  
  329.    Since both the first condition and the second condition must be true
  330. together, the two expressions, the region test and the search
  331. expression, can be joined with an `and' special form and embedded in
  332. the `while' loop as the true-or-false-test, like this:
  333.  
  334.      (and (< (point) end) (re-search-forward "\\w+\\W*" end t))
  335.  
  336. (*Note forward-paragraph::, for information about `and'.)
  337.  
  338.    The `re-search-forward' expression returns `t' if the search
  339. succeeds and as a side effect moves point.  Consequently, as words are
  340. found, point is moved through the region.  When the search expression
  341. fails to find another word, or when point reaches the end of the
  342. region, the true-or-false-test tests false, the `while' loop exists,
  343. and the `count-words-region' function displays one or other of its
  344. messages.
  345.  
  346.    After incorporating these final changes, the `count-words-region'
  347. works without bugs (or at least, without bugs that I have found!).
  348. Here is what it looks like:
  349.  
  350.      ;;; Final version: `while'
  351.      (defun count-words-region (beginning end)
  352.        "Print number of words in the region."
  353.        (interactive "r")
  354.        (message "Counting words in region ... ")
  355.      
  356.      ;;; 1. Set up appropriate conditions.
  357.        (save-excursion
  358.          (let ((count 0))
  359.            (goto-char beginning)
  360.      
  361.      ;;; 2. Run the while loop.
  362.            (while (and (< (point) end)
  363.                        (re-search-forward "\\w+\\W*" end t))
  364.              (setq count (1+ count)))
  365.      
  366.      ;;; 3. Send a message to the user.
  367.            (cond ((zerop count)
  368.                   (message
  369.                    "The region does NOT have any words."))
  370.                  ((= 1 count)
  371.                   (message
  372.                    "The region has 1 word."))
  373.                  (t
  374.                   (message
  375.                    "The region has %d words." count))))))
  376.  
  377. 
  378. File: emacs-lisp-intro.info,  Node: recursive-count-words,  Next: Counting Exercise,  Prev: count-words-region,  Up: Counting Words
  379.  
  380. Count Words Recursively
  381. =======================
  382.  
  383.    You can write the function for counting words recursively as well as
  384. with a `while' loop.  Let's see how this is done.
  385.  
  386.    First, we need to recognize that the `count-words-region' function
  387. has three jobs: it sets up the appropriate conditions for counting to
  388. occur; it counts the words in the region; and it sends a message to the
  389. user telling how many words there are.
  390.  
  391.    If we write a single recursive function to do everything, we will
  392. receive a message for every recursive call.  If the region contains 13
  393. words, we will receive thirteen messages, one right after the other.
  394. We don't want this!  Instead, we must write two functions to do the
  395. job, one of which (the recursive function) will be used inside of the
  396. other.  One function will set up the conditions and display the
  397. message; the other will return the word count.
  398.  
  399.    Let us start with the function that causes the message to be
  400. displayed.  We can continue to call this `count-words-region'.
  401.  
  402.    This is the function that the user will call.  It will be
  403. interactive.  Indeed, it will be similar to our previous versions of
  404. this function, except that it will call `recursive-count-words' to
  405. determine how many words are in the region.
  406.  
  407.    We can readily construct a template for this function, based on our
  408. previous versions:
  409.  
  410.      ;; Recursive version; uses regular expression search
  411.      (defun count-words-region (beginning end)
  412.        "DOCUMENTATION..."
  413.        (INTERACTIVE-EXPRESSION...)
  414.      
  415.      ;;; 1. Set up appropriate conditions.
  416.        (EXPLANATORY MESSAGE)
  417.        (SET-UP FUNCTIONS...
  418.      
  419.      ;;; 2. Count the words.
  420.          RECURSIVE CALL
  421.      
  422.      ;;; 3. Send a message to the user.
  423.          MESSAGE PROVIDING WORD COUNT))
  424.  
  425.    The definition looks straightforward, except that somehow the count
  426. returned by the recursive call must be passed to the message displaying
  427. the word count.  A little thought suggests that this can be done by
  428. making use of a `let' expression: we can bind a variable in the varlist
  429. of a `let' expression to the number of words in the region, as returned
  430. by the recursive call; and then the `cond' expression, using binding,
  431. can display the value to the user.
  432.  
  433.    Often, one thinks of the binding within a `let' expression as
  434. somehow secondary to the `primary' work of a function.  But in this
  435. case, what you might consider the `primary' job of the function,
  436. counting words, is done within the `let' expression.
  437.  
  438.    Using `let', the function definition looks like this:
  439.  
  440.      (defun count-words-region (beginning end)
  441.        "Print number of words in the region."
  442.        (interactive "r")
  443.      
  444.      ;;; 1. Set up appropriate conditions.
  445.        (message "Counting words in region ... ")
  446.        (save-excursion
  447.          (goto-char beginning)
  448.      
  449.      ;;; 2. Count the words.
  450.          (let ((count (recursive-count-words end)))
  451.      
  452.      ;;; 3. Send a message to the user.
  453.            (cond ((zerop count)
  454.                   (message
  455.                    "The region does NOT have any words."))
  456.                  ((= 1 count)
  457.                   (message
  458.                    "The region has 1 word."))
  459.                  (t
  460.                   (message
  461.                    "The region has %d words." count))))))
  462.  
  463.    Next, we need to write the recursive counting function.
  464.  
  465.    A recursive function has at least three parts: the `do-again-test',
  466. the `next-step-expression', and the recursive call.
  467.  
  468.    The do-again-test determines whether the function will or will not be
  469. called again.  Since we are counting words in a region and can use a
  470. function that moves point forward for every word, the do-again-test can
  471. check whether point is still within the region.  The do-again-test
  472. should find the value of point and determine whether point is before,
  473. at, or after the value of the end of the region.  We can use the
  474. `point' function to locate point.  Clearly, we must pass the value of
  475. the end of the region to the recursive counting function as an argument.
  476.  
  477.    In addition, the do-again-test should also test whether the search
  478. finds a word.  If it does not, the function should not call itself
  479. again.
  480.  
  481.    The next-step-expression changes a value so that when the recursive
  482. function is supposed to stop calling itself, it stops.  More precisely,
  483. the next-step-expression changes a value so that at the right time, the
  484. do-again-test stops the recursive function from calling itself again.
  485. In this case, the next-step-expression can be the expression that moves
  486. point forward, word by word.
  487.  
  488.    The third part of a recursive function is the recursive call.
  489.  
  490.    Somewhere, also, we also need a part that does the `work' of the
  491. function, a part that does the counting.  A vital part!
  492.  
  493.    But already, we have an outline of the recursive counting function:
  494.  
  495.      (defun recursive-count-words (region-end)
  496.        "DOCUMENTATION..."
  497.         DO-AGAIN-TEST
  498.         NEXT-STEP-EXPRESSION
  499.         RECURSIVE CALL)
  500.  
  501.    Now we need to fill in the slots.  Let's start with the simplest
  502. cases first:  if point is at or beyond the end of the region, there
  503. cannot be any words in the region, so the function should return zero.
  504. Likewise, if the search fails, there are no words to count, so the
  505. function should return zero.
  506.  
  507.    On the other hand, if point is within the region and the search
  508. succeeds, the function should call itself again.
  509.  
  510.    Thus, the do-again-test should look like this:
  511.  
  512.      (and (< (point) region-end)
  513.           (re-search-forward "\\w+\\W*" region-end t))
  514.  
  515.    Note that the search expression is part of the do-again-test--the
  516. function returns `t' if its search succeeds and `nil' if it fails.
  517. (*Note The Whitespace Bug in `count-words-region': Whitespace Bug, for
  518. an explanation of how `re-search-forward' works.)
  519.  
  520.    The do-again-test is the true-or-false test of an `if' clause.
  521. Clearly, if the do-again-test succeeds, the then-part of the `if'
  522. clause should call the function again; but if it fails, the else-part
  523. should return zero since either point is outside the region or the
  524. search failed because there were no words to find.
  525.  
  526.    But before considering the recursive call, we need to consider the
  527. next-step-expression.  What is it?  Interestingly, it is the search
  528. part of the do-again-test.
  529.  
  530.    In addition to returning `t' or `nil' for the do-again-test,
  531. `re-search-forward' moves point forward as a side effect of a
  532. successful search.  This is the action that changes the value of point
  533. so that the recursive function stops calling itself when point
  534. completes its movement through the region.  Consequently, the
  535. `re-search-forward' expression is the next-step-expression.
  536.  
  537.    In outline, then, the body of the `recursive-count-words' function
  538. looks like this:
  539.  
  540.      (if DO-AGAIN-TEST-AND-NEXT-STEP-COMBINED
  541.          ;; then
  542.          RECURSIVE-CALL-RETURNING-COUNT
  543.        ;; else
  544.        RETURN-ZERO)
  545.  
  546.    How to incorporate the mechanism that counts?
  547.  
  548.    If you are not used to writing recursive functions, a question like
  549. this can be troublesome.  But it can and should be approached
  550. systematically.
  551.  
  552.    We know that the counting mechanism should be associated in some way
  553. with the recursive call.  Indeed, since the next-step-expression moves
  554. point forward by one word, and since a recursive call is made for each
  555. word, the counting mechanism must be an expression that adds one to the
  556. value returned by a call to `recursive-count-words'.
  557.  
  558.    Consider several cases:
  559.  
  560.    * If there are two words in the region, the function should return a
  561.      value resulting from adding one to the value returned when it
  562.      counts the first word, plus the number returned when it counts the
  563.      remaining words in the region, which in this case is one.
  564.  
  565.    * If there is one word in the region, the function should return a
  566.      value resulting from adding one to the value returned when it
  567.      counts that word, plus the number returned when it counts the
  568.      remaining words in the region, which in this case is zero.
  569.  
  570.    * If there are no words in the region, the function should return
  571.      zero.
  572.  
  573.    From the sketch we can see that the else-part of the `if' returns
  574. zero for the case of no words.  This means that the then-part of the
  575. `if' must return a value resulting from adding one to the value
  576. returned from a count of the remaining words.
  577.  
  578.    The expression will look like this, where `1+' is a function that
  579. adds one to its argument.
  580.  
  581.      (1+ (recursive-count-words region-end))
  582.  
  583.    The whole `recursive-count-words' function will then look like this:
  584.  
  585.      (defun recursive-count-words (region-end)
  586.        "DOCUMENTATION..."
  587.      
  588.      ;;; 1. do-again-test
  589.        (if (and (< (point) region-end)
  590.                 (re-search-forward "\\w+\\W*" region-end t))
  591.      
  592.      ;;; 2. then-part: the recursive call
  593.            (1+ (recursive-count-words region-end))
  594.      
  595.      ;;; 3. else-part
  596.          0))
  597.  
  598.    Let's examine how this works:
  599.  
  600.    If there are no words in the region, the else part of the `if'
  601. expression is evaluated and consequently the function returns zero.
  602.  
  603.    If there is one word in the region, the value of point is less than
  604. the value of `region-end' and the search succeeds.  In this case, the
  605. true-or-false-test of the `if' expression tests true, and the then-part
  606. of the `if' expression is evaluated.  The counting expression is
  607. evaluated.  This expression returns a value (which will be the value
  608. returned by the whole function) that is the sum of one added to the
  609. value returned by a recursive call.
  610.  
  611.    Meanwhile, the next-step-expression has caused point to jump over the
  612. first (and in this case only) word in the region.  This means that when
  613. `(recursive-count-words region-end)' is evaluated a second time, as a
  614. result of the recursive call, the value of point will be equal to or
  615. greater than the value of region end.  So this time,
  616. `recursive-count-words' will return zero.  The zero will be added to
  617. one, and the original evaluation of `recursive-count-words' will return
  618. one plus zero, which is one, which is the correct amount.
  619.  
  620.    Clearly, if there are two words in the region, the first call to
  621. `recursive-count-words' returns one added to the value returned by
  622. calling `recursive-count-words' on a region containing the remaining
  623. word--that is, it adds one to one, producing two, which is the correct
  624. amount.
  625.  
  626.    Similarly, if there are three words in the region, the first call to
  627. `recursive-count-words' returns one added to the value returned by
  628. calling `recursive-count-words' on a region containing the remaining
  629. two words--and so on and so on.
  630.  
  631. With full documentation the two functions look like this:
  632.  
  633. The recursive function:
  634.  
  635.      (defun recursive-count-words (region-end)
  636.        "Number of words between point and REGION-END."
  637.      
  638.      ;;; 1. do-again-test
  639.        (if (and (< (point) region-end)
  640.                 (re-search-forward "\\w+\\W*" region-end t))
  641.      
  642.      ;;; 2. then-part: the recursive call
  643.            (1+ (recursive-count-words region-end))
  644.      
  645.      ;;; 3. else-part
  646.          0))
  647.  
  648. The wrapper:
  649.  
  650.      ;;; Recursive version
  651.      (defun count-words-region (beginning end)
  652.        "Print number of words in the region.
  653.      
  654.      Words are defined as at least one word-constituent
  655.      character followed by at least one character that is
  656.      not a word-constituent.  The buffer's syntax table
  657.      determines which characters these are."
  658.        (interactive "r")
  659.        (message "Counting words in region ... ")
  660.        (save-excursion
  661.          (goto-char beginning)
  662.          (let ((count (recursive-count-words end)))
  663.            (cond ((zerop count)
  664.                   (message
  665.                    "The region does NOT have any words."))
  666.                  ((= 1 count)
  667.                   (message "The region has 1 word."))
  668.                  (t
  669.                   (message
  670.                    "The region has %d words." count))))))
  671.  
  672. 
  673. File: emacs-lisp-intro.info,  Node: Counting Exercise,  Prev: recursive-count-words,  Up: Counting Words
  674.  
  675. Exercise: Counting Punctuation
  676. ==============================
  677.  
  678.    Using a `while' loop, write a function to count the number of
  679. punctuation marks in a region--period, comma, semicolon, colon,
  680. exclamation mark, and question mark.  Do the same using recursion.
  681.  
  682. 
  683. File: emacs-lisp-intro.info,  Node: Words in a defun,  Next: Readying a Graph,  Prev: Counting Words,  Up: Top
  684.  
  685. Counting Words in a `defun'
  686. ***************************
  687.  
  688.    Our next project is to count the number of words in a function
  689. definition.  Clearly, this can be done using some variant of
  690. `count-word-region'.  *Note Counting Words: Repetition and Regexps:
  691. Counting Words.  If we are just going to count the words in one
  692. definition, it is easy enough to mark the definition with the `C-M-h'
  693. (`mark-defun') command, and then call `count-word-region'.
  694.  
  695.    However, I am more ambitious: I want to count the words and symbols
  696. in every definition in the Emacs sources and then print a graph that
  697. shows how many functions there are of each length: how many contain 40
  698. to 49 words or symbols, how many contain 50 to 59 words or symbols, and
  699. so on.  I have often been curious how long a typical function is, and
  700. this will tell.
  701.  
  702. * Menu:
  703.  
  704. * Divide and Conquer::
  705. * Words and Symbols::           What to count?
  706. * Syntax::                      What constitutes a word or symbol?
  707. * count-words-in-defun::        Very like `count-words'.
  708. * Several defuns::              Counting several defuns in a file.
  709. * Find a File::                 Do you want to look at a file?
  710. * lengths-list-file::           A list of the lengths of many definitions.
  711. * Several files::               Counting in definitions in different files.
  712. * Several files recursively::   Recursively counting in different files.
  713. * Prepare the data::            Prepare the data for display in a graph.
  714.  
  715. 
  716. File: emacs-lisp-intro.info,  Node: Divide and Conquer,  Next: Words and Symbols,  Prev: Words in a defun,  Up: Words in a defun
  717.  
  718. Divide and Conquer
  719. ==================
  720.  
  721.    Described in one phrase, the histogram project is daunting; but
  722. divided into numerous small steps, each of which we can take one at a
  723. time, the project becomes less fearsome.  Let us consider what the
  724. steps must be:
  725.  
  726.    * First, write a function to count the words in one definition.  This
  727.      includes the problem of handling symbols as well as words.
  728.  
  729.    * Second, write a function to list the numbers of words in each
  730.      function in a file.  This function can use the
  731.      `count-words-in-defun' function.
  732.  
  733.    * Third, write a function to list the numbers of words in each
  734.      function in each of several files.  This entails automatically
  735.      finding the various files, switching to them, and counting the
  736.      words in the definitions within them.
  737.  
  738.    * Fourth, write a function to convert the list of numbers that we
  739.      created in step three to a form that will be suitable for printing
  740.      as a graph.
  741.  
  742.    * Fifth, write a function to print the results as a graph.
  743.  
  744.    This is quite a project!  But if we take each step slowly, it will
  745. not be difficult.
  746.  
  747. 
  748. File: emacs-lisp-intro.info,  Node: Words and Symbols,  Next: Syntax,  Prev: Divide and Conquer,  Up: Words in a defun
  749.  
  750. What to Count?
  751. ==============
  752.  
  753.    When we first start thinking about how to count the words in a
  754. function definition, the first question is (or ought to be) what are we
  755. going to count?  When we speak of `words' with respect to a Lisp
  756. function definition, we are actually speaking, in large part, of
  757. `symbols'.  For example, the following `multiply-by-seven' function
  758. contains the five symbols `defun', `multiply-by-seven', `number', `*',
  759. and `7'.  In addition, in the documentation string, it contains the
  760. four words `Multiply', `NUMBER', `by', and `seven'.  The symbol
  761. `number' is repeated, so the definition contains a total of ten words
  762. and symbols.
  763.  
  764.      (defun multiply-by-seven (number)
  765.        "Multiply NUMBER by seven."
  766.        (* 7 number))
  767.  
  768. However, if we mark the `multiply-by-seven' definition with `C-M-h'
  769. (`mark-defun'), and then call `count-words-region' on it, we will find
  770. that `count-words-region' claims the definition has eleven words, not
  771. ten!  Something is wrong!
  772.  
  773.    The problem is twofold: `count-words-region' does not count the `*'
  774. as a word, and it counts the single symbol, `multiply-by-seven', as
  775. containing three words.  The hyphens are treated as if they were
  776. interword spaces rather than intraword connectors: `multiply-by-seven'
  777. is counted as if it were written `multiply by seven'.
  778.  
  779.    The cause of this confusion is the regular expression search within
  780. the `count-words-region' definition that moves point forward word by
  781. word.  In the canonical version of `count-words-region', the regexp is:
  782.  
  783.      "\\w+\\W*"
  784.  
  785. This regular expression is a pattern defining one or more word
  786. constituent characters possibly followed by one or more characters that
  787. are not word constituents.  What is meant by `word constituent
  788. characters' brings us to the issue of syntax, which is worth a section
  789. of its own.
  790.  
  791. 
  792. File: emacs-lisp-intro.info,  Node: Syntax,  Next: count-words-in-defun,  Prev: Words and Symbols,  Up: Words in a defun
  793.  
  794. What Constitutes a Word or Symbol?
  795. ==================================
  796.  
  797.    Emacs treats different characters as belonging to different "syntax
  798. categories".  For example, the regular expression, `\\w+', is a pattern
  799. specifying one or more _word constituent_ characters.  Word constituent
  800. characters are members of one syntax category.  Other syntax categories
  801. include the class of punctuation characters, such as the period and the
  802. comma, and the class of whitespace characters, such as the blank space
  803. and the tab character.  (For more information, see *Note Syntax:
  804. (emacs)Syntax, and *Note Syntax Tables: (elisp)Syntax Tables.)
  805.  
  806.    Syntax tables specify which characters belong to which categories.
  807. Usually, a hyphen is not specified as a `word constituent character'.
  808. Instead, it is specified as being in the `class of characters that are
  809. part of symbol names but not words.'  This means that the
  810. `count-words-region' function treats it in the same way it treats an
  811. interword white space, which is why `count-words-region' counts
  812. `multiply-by-seven' as three words.
  813.  
  814.    There are two ways to cause Emacs to count `multiply-by-seven' as
  815. one symbol: modify the syntax table or modify the regular expression.
  816.  
  817.    We could redefine a hyphen as a word constituent character by
  818. modifying the syntax table that Emacs keeps for each mode.  This action
  819. would serve our purpose, except that a hyphen is merely the most common
  820. character within symbols that is not typically a word constituent
  821. character; there are others, too.
  822.  
  823.    Alternatively, we can redefine the regular expression used in the
  824. `count-words' definition so as to include symbols.  This procedure has
  825. the merit of clarity, but the task is a little tricky.
  826.  
  827.    The first part is simple enough: the pattern must match "at least one
  828. character that is a word or symbol constituent".  Thus:
  829.  
  830.      "\\(\\w\\|\\s_\\)+"
  831.  
  832. The `\\(' is the first part of the grouping construct that includes the
  833. `\\w' and the `\\s_' as alternatives, separated by the `\\|'.  The
  834. `\\w' matches any word-constituent character and the `\\s_' matches any
  835. character that is part of a symbol name but not a word-constituent
  836. character.  The `+' following the group indicates that the word or
  837. symbol constituent characters must be matched at least once.
  838.  
  839.    However, the second part of the regexp is more difficult to design.
  840. What we want is to follow the first part with "optionally one or more
  841. characters that are not constituents of a word or symbol".  At first, I
  842. thought I could define this with the following:
  843.  
  844.      "\\(\\W\\|\\S_\\)*"
  845.  
  846. The upper case `W' and `S' match characters that are _not_ word or
  847. symbol constituents.  Unfortunately, this expression matches any
  848. character that is either not a word constituent or not a symbol
  849. constituent.  This matches any character!
  850.  
  851.    I then noticed that every word or symbol in my test region was
  852. followed by white space (blank space, tab, or newline).  So I tried
  853. placing a pattern to match one or more blank spaces after the pattern
  854. for one or more word or symbol constituents.  This failed, too.  Words
  855. and symbols are often separated by whitespace, but in actual code
  856. parentheses may follow symbols and punctuation may follow words.  So
  857. finally, I designed a pattern in which the word or symbol constituents
  858. are followed optionally by characters that are not white space and then
  859. followed optionally by white space.
  860.  
  861.    Here is the full regular expression:
  862.  
  863.      "\\(\\w\\|\\s_\\)+[^ \t\n]*[ \t\n]*"
  864.  
  865. 
  866. File: emacs-lisp-intro.info,  Node: count-words-in-defun,  Next: Several defuns,  Prev: Syntax,  Up: Words in a defun
  867.  
  868. The `count-words-in-defun' Function
  869. ===================================
  870.  
  871.    We have seen that there are several ways to write a
  872. `count-word-region' function.  To write a `count-words-in-defun', we
  873. need merely adapt one of these versions.
  874.  
  875.    The version that uses a `while' loop is easy to understand, so I am
  876. going to adapt that.  Because `count-words-in-defun' will be part of a
  877. more complex program, it need not be interactive and it need not
  878. display a message but just return the count.  These considerations
  879. simplify the definition a little.
  880.  
  881.    On the other hand, `count-words-in-defun' will be used within a
  882. buffer that contains function definitions.  Consequently, it is
  883. reasonable to ask that the function determine whether it is called when
  884. point is within a function definition, and if it is, to return the
  885. count for that definition.  This adds complexity to the definition, but
  886. saves us from needing to pass arguments to the function.
  887.  
  888.    These considerations lead us to prepare the following template:
  889.  
  890.      (defun count-words-in-defun ()
  891.        "DOCUMENTATION..."
  892.        (SET UP...
  893.           (WHILE LOOP...)
  894.         RETURN COUNT)
  895.  
  896. As usual, our job is to fill in the slots.
  897.  
  898.    First, the set up.
  899.  
  900.    We are presuming that this function will be called within a buffer
  901. containing function definitions.  Point will either be within a
  902. function definition or not.  For `count-words-in-defun' to work, point
  903. must move to the beginning of the definition, a counter must start at
  904. zero, and the counting loop must stop when point reaches the end of the
  905. definition.
  906.  
  907.    The `beginning-of-defun' function searches backwards for an opening
  908. delimiter such as a `(' at the beginning of a line, and moves point to
  909. that position, or else to the limit of the search.  In practice, this
  910. means that `beginning-of-defun' moves point to the beginning of an
  911. enclosing or preceding function definition, or else to the beginning of
  912. the buffer.  We can use `beginning-of-defun' to place point where we
  913. wish to start.
  914.  
  915.    The `while' loop requires a counter to keep track of the words or
  916. symbols being counted.  A `let' expression can be used to create a
  917. local variable for this purpose, and bind it to an initial value of
  918. zero.
  919.  
  920.    The `end-of-defun' function works like `beginning-of-defun' except
  921. that it moves point to the end of the definition.  `end-of-defun' can
  922. be used as part of an expression that determines the position of the
  923. end of the definition.
  924.  
  925.    The set up for `count-words-in-defun' takes shape rapidly: first we
  926. move point to the beginning of the definition, then we create a local
  927. variable to hold the count, and finally, we record the position of the
  928. end of the definition so the `while' loop will know when to stop
  929. looping.
  930.  
  931.    The code looks like this:
  932.  
  933.      (beginning-of-defun)
  934.      (let ((count 0)
  935.            (end (save-excursion (end-of-defun) (point))))
  936.  
  937. The code is simple.  The only slight complication is likely to concern
  938. `end': it is bound to the position of the end of the definition by a
  939. `save-excursion' expression that returns the value of point after
  940. `end-of-defun' temporarily moves it to the end of the definition.
  941.  
  942.    The second part of the `count-words-in-defun', after the set up, is
  943. the `while' loop.
  944.  
  945.    The loop must contain an expression that jumps point forward word by
  946. word and symbol by symbol, and another expression that counts the
  947. jumps.  The true-or-false-test for the `while' loop should test true so
  948. long as point should jump forward, and false when point is at the end
  949. of the definition.  We have already redefined the regular expression
  950. for this (*note Syntax::), so the loop is straightforward:
  951.  
  952.      (while (and (< (point) end)
  953.                  (re-search-forward
  954.                   "\\(\\w\\|\\s_\\)+[^ \t\n]*[ \t\n]*" end t)
  955.        (setq count (1+ count)))
  956.  
  957.    The third part of the function definition returns the count of words
  958. and symbols.  This part is the last expression within the body of the
  959. `let' expression, and can be, very simply, the local variable `count',
  960. which when evaluated returns the count.
  961.  
  962.    Put together, the `count-words-in-defun' definition looks like this:
  963.  
  964.      (defun count-words-in-defun ()
  965.        "Return the number of words and symbols in a defun."
  966.        (beginning-of-defun)
  967.        (let ((count 0)
  968.              (end (save-excursion (end-of-defun) (point))))
  969.          (while
  970.              (and (< (point) end)
  971.                   (re-search-forward
  972.                    "\\(\\w\\|\\s_\\)+[^ \t\n]*[ \t\n]*"
  973.                    end t))
  974.            (setq count (1+ count)))
  975.          count))
  976.  
  977.    How to test this?  The function is not interactive, but it is easy to
  978. put a wrapper around the function to make it interactive; we can use
  979. almost the same code as for the recursive version of
  980. `count-words-region':
  981.  
  982.      ;;; Interactive version.
  983.      (defun count-words-defun ()
  984.        "Number of words and symbols in a function definition."
  985.        (interactive)
  986.        (message
  987.         "Counting words and symbols in function definition ... ")
  988.        (let ((count (count-words-in-defun)))
  989.          (cond
  990.           ((zerop count)
  991.            (message
  992.             "The definition does NOT have any words or symbols."))
  993.           ((= 1 count)
  994.            (message
  995.             "The definition has 1 word or symbol."))
  996.           (t
  997.            (message
  998.             "The definition has %d words or symbols." count)))))
  999.  
  1000. Let's re-use `C-c =' as a convenient keybinding:
  1001.  
  1002.      (global-set-key "\C-c=" 'count-words-defun)
  1003.  
  1004.    Now we can try out `count-words-defun': install both
  1005. `count-words-in-defun' and `count-words-defun', and set the keybinding,
  1006. and then place the cursor within the following definition:
  1007.  
  1008.      (defun multiply-by-seven (number)
  1009.        "Multiply NUMBER by seven."
  1010.        (* 7 number))
  1011.           => 10
  1012.  
  1013. Success!  The definition has 10 words and symbols.
  1014.  
  1015.    The next problem is to count the numbers of words and symbols in
  1016. several definitions within a single file.
  1017.  
  1018. 
  1019. File: emacs-lisp-intro.info,  Node: Several defuns,  Next: Find a File,  Prev: count-words-in-defun,  Up: Words in a defun
  1020.  
  1021. Count Several `defuns' Within a File
  1022. ====================================
  1023.  
  1024.    A file such as `simple.el' may have 80 or more function definitions
  1025. within it.  Our long term goal is to collect statistics on many files,
  1026. but as a first step, our immediate goal is to collect statistics on one
  1027. file.
  1028.  
  1029.    The information will be a series of numbers, each number being the
  1030. length of a function definition.  We can store the numbers in a list.
  1031.  
  1032.    We know that we will want to incorporate the information regarding
  1033. one file with information about many other files; this means that the
  1034. function for counting definition lengths within one file need only
  1035. return the list of lengths.  It need not and should not display any
  1036. messages.
  1037.  
  1038.    The word count commands contain one expression to jump point forward
  1039. word by word and another expression to count the jumps.  The function
  1040. to return the lengths of definitions can be designed to work the same
  1041. way, with one expression to jump point forward definition by definition
  1042. and another expression to construct the lengths' list.
  1043.  
  1044.    This statement of the problem makes it elementary to write the
  1045. function definition.  Clearly, we will start the count at the beginning
  1046. of the file, so the first command will be `(goto-char (point-min))'.
  1047. Next, we start the `while' loop; and the true-or-false test of the loop
  1048. can be a regular expression search for the next function definition--so
  1049. long as the search succeeds, point is moved forward and then the body
  1050. of the loop is evaluated.  The body needs an expression that constructs
  1051. the lengths' list.  `cons', the list construction command, can be used
  1052. to create the list.  That is almost all there is to it.
  1053.  
  1054.    Here is what this fragment of code looks like:
  1055.  
  1056.      (goto-char (point-min))
  1057.      (while (re-search-forward "^(defun" nil t)
  1058.        (setq lengths-list
  1059.              (cons (count-words-in-defun) lengths-list)))
  1060.  
  1061.    What we have left out is the mechanism for finding the file that
  1062. contains the function definitions.
  1063.  
  1064.    In previous examples, we either used this, the Info file, or we
  1065. switched back and forth to some other buffer, such as the `*scratch*'
  1066. buffer.
  1067.  
  1068.    Finding a file is a new process that we have not yet discussed.
  1069.  
  1070. 
  1071. File: emacs-lisp-intro.info,  Node: Find a File,  Next: lengths-list-file,  Prev: Several defuns,  Up: Words in a defun
  1072.  
  1073. Find a File
  1074. ===========
  1075.  
  1076.    To find a file in Emacs, you use the `C-x C-f' (`find-file')
  1077. command.  This command is almost, but not quite right for the lengths
  1078. problem.
  1079.  
  1080.    Let's look at the source for `find-file' (you can use the `find-tag'
  1081. command or `C-h f' (`describe-function') to find the source of a
  1082. function):
  1083.  
  1084.      (defun find-file (filename)
  1085.        "Edit file FILENAME.
  1086.      Switch to a buffer visiting file FILENAME,
  1087.      creating one if none already exists."
  1088.        (interactive "FFind file: ")
  1089.        (switch-to-buffer (find-file-noselect filename)))
  1090.  
  1091.    The definition possesses short but complete documentation and an
  1092. interactive specification that prompts you for a file name when you use
  1093. the command interactively.  The body of the definition contains two
  1094. functions, `find-file-noselect' and `switch-to-buffer'.
  1095.  
  1096.    According to its documentation as shown by `C-h f' (the
  1097. `describe-function' command), the `find-file-noselect' function reads
  1098. the named file into a buffer and returns the buffer.  However, the
  1099. buffer is not selected.  Emacs does not switch its attention (or yours
  1100. if you are using `find-file-noselect') to the named buffer.  That is
  1101. what `switch-to-buffer' does: it switches the buffer to which Emacs
  1102. attention is directed; and it switches the buffer displayed in the
  1103. window to the new buffer.  We have discussed buffer switching
  1104. elsewhere.  (*Note Switching Buffers::.)
  1105.  
  1106.    In this histogram project, we do not need to display each file on the
  1107. screen as the program determines the length of each definition within
  1108. it.  Instead of employing `switch-to-buffer', we can work with
  1109. `set-buffer', which redirects the attention of the computer program to
  1110. a different buffer but does not redisplay it on the screen.  So instead
  1111. of calling on `find-file' to do the job, we must write our own
  1112. expression.
  1113.  
  1114.    The task is easy: use  `find-file-noselect' and `set-buffer'.
  1115.  
  1116.